// locutor command line client
// (c) 2009, Normen Müller, normen.mueller@gmail.com  
// $Id: Locutor.scala 90 2010-05-11 22:13:56Z normen.mueller $
package locutor.draft.demo

/** A Change Impact Analysis workflow demonstation powered by locutor.
 * 
 * @todo ad hoc document type specific configurations, i.e. mapping of MIME/ DTD/ Document to a configuration
 *       comprising an equivalence specification, a graph model, and a rule system.  User annotations extending
 *       the computed dependency graph are optional.
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.5 */
//object Locutor { 
//  
//  def main(args: Array[String]) {
//    // === Initialize system environment
//    initialize
//    
//    // === Create a collection of documents C whereas each document Doc has an associated document model M. For each document Doc within a document collection C, the associated graph model G
//    // === is extended by the structural node types N_syn and structural link types L_syn of Doc, such that M(Doc) = <E, G join (N_syn, L_syn), R>.
//    val C = DocumentCollection("wedding",
//      ("etc/data/wedding/guests.xml", DocumentModel("wedding/guests.eq", "wedding/guests.gm", "wedding/guests.rs")),
//      ("etc/data/wedding/seating.xml", DocumentModel("wedding/seating.eq", "wedding/seating.gm", "wedding/seating.rs")))    
//    // === Flush associated document models and verify if flushed output is adequate, i.e. parsing the flushed output again must not result in parsing errors.  Note that already during creation
//    // ==  of a document collection existence of respective documents is verified.
//    validate(C)    
//    
//    // === Simulate a change
//    // v1: modification: list of invited guests permuted | deltas: empty | effects: none
//    "etc/data/wedding/guestsv1.xml".toFile copyTo "etc/data/wedding/guests.xml".toFile
//    
//    // === Semantic difference analysis
//    val Δ = C.analyze    
//    // === Flush identified differences
//    flush(Δ)
//        
//    // === Semantic dependency analysis
//    // === For each document within the document collection the dependency graph is computed comprising structural as well as semanitc nodes and links.  In addition one can add ``manual''
//    // === annotations, i.e. not inferrable annotations.
//    implicit val D = C.annotate /*(
//      ("etc/data/wedding/guests.xml", "guests-exttannos.grs"),
//      ("etc/data/wedding/seating.xml", "seating-exttannos.grs")
//    )*/    
//    // === Flush dependency graphs and verify if flushed output is adequate.
//    validate(D)
//    
//    // === Change impact analysis
//    // === Note the for using ``↩'' a semantic dependency analysis has to be implicitly given.  Otherwise use ``ripple'' explicitly, like C.ripple(D, Δ).
////    val I = C ↩ Δ
//    
//    // === Revert simulated change
//    // v1: list of invited guests permuted -> No change
//    "etc/data/wedding/guestsv0.xml".toFile copyTo "etc/data/wedding/guests.xml".toFile
//  }
//  
//  /* System configuration
//   * @todo Externalize to XML configuration file */
//  def initialize = {
//    System.setProperty("locutor.tmp",   "/Users/nmueller/tmp/locutor")  // temporary directory
//    System.setProperty("locutor.grgen", "/opt/grgen/bin")               // GrGen home directory
//    System.setProperty("locutor.equiv", "etc/kb/eq")                    // Knowledge base | Equivalence Specifications
//    System.setProperty("locutor.types", "etc/kb/gm")                    // Knowledge base | Graph Models
//    System.setProperty("locutor.rules", "etc/kb/rs")                    // Knowledge base | Rule Systems
//  }
//  
//  def validate(collection: DocumentCollection) {
//    collection foreach (_ match { case (document, model) =>
//      try {
//        println("validating document model of \""+document.name+"\"")
//        print("... equivalence system")
//        scalaxx.diff.EquivalenceSystem.parse(model.equivSys.toString)
//        model.equivSys.toString >>> (System.getProperty("locutor.tmp").toFile / (document.label + ".eq"))
//        println(" ok")
//      } catch {
//        case e:Exception =>
//          println("Equivalence Specification validation error.")
//          throw e
//      }        
//      try {
//        print("... graph model (1)")
//        GraphModel.parse("model V { " + model.graphModel.toGrGen + "}")
//        println("    ok")
//        print("... graph model (2)")
//        GrGen.validate(model.graphModel)
//        println("    ok")
//      } catch {
//        case e:Exception =>
//          println("Graph Model validation error.")
//          throw e
//      }
//    })    
//  }
//  
//  def validate(dependencies: Map[File, DependencyGraph]) =
//    dependencies foreach (_ match { case (document, graph) =>
//      try {
//        println("validating dependency graph of \""+document.name+"\"")
//        print("... dependency graph")
//        GrGen.validate(graph)
//        println("    ok")
//      } catch {
//        case e:Exception =>
//          println("Dependency Graph validation error.")
//          throw e
//      }                       
//    })
//  
//  def flush(infos: Map[File, _]) {
//    for(info <- infos) info match {
//      case (document, commands: List[_])      => (commands mkString "\n") >>> (System.getProperty("locutor.tmp").toFile / (document.label + ".diff"))
//      case (document, graph: DependencyGraph) => graph.toGrShell >>> (System.getProperty("locutor.tmp").toFile / (document.label + ".dep"))
//    }
//  }
//  
//}

//object LocutorTst {
//  
//  def main(args: Array[String]) {
//    
//    // config
//    System.setProperty("locutor.tmp",    "/Users/nmueller/tmp/locutor")
//    System.setProperty("locutor.grgen",  "/opt/grgen/bin")
//    System.setProperty("locutor.equivs", "etc/kb/eq")
//    System.setProperty("locutor.models", "etc/kb/gm")
//    System.setProperty("locutor.rules",  "etc/kb/rs")
//    
//    val LOCUTOR_EQUIVS = System.getProperty("locutor.equivs").toFile
//    val LOCUTOR_RULES  = System.getProperty("locutor.rules").toFile
//    
//    val orgFile = "etc/data/svnbook/svnbook.xml".toFile
//    
//    // ---------------------------------------------------
//    // ``<preface id="svn.foreword">'' removed    
//    val modFile = "etc/data/svnbook/svnbook-v1.xml".toFile
//    
//    // ``<preface id="svn.foreword">'' removed
//    // ``<indexterm>'' removed
//    //val modFile = "etc/data/svnbook/svnbook-v2.xml".toFile
//    // ---------------------------------------------------
//
//    // parameters
//    val args = Array[String](
//      "etc/data/svnbook/svnbook.dg",        // dependency graph
//      (LOCUTOR_EQUIVS / "svnbook.eq").path, // equivalence system
//      (LOCUTOR_RULES / "svnbook.rs").path,  // rule system
//      orgFile.path,                         // old file
//      modFile.path                          // modified file
//    )
//      
//    locutor.cli.Locutor.main(args)
//                                                              
//enum CT {none, removed, reordered, renamed, rephrased}
//enum DT {ident, name, position, literal, size, url}
//abstract directed edge class Dependency connect Infom --> Infom { via: set<string> = { "ident" }; }
//edge class dependsOn extends Dependency connect Infom --> Infom[+];
// directed:
//edge class dependsOn extends Dependency connect Infom[+] --> Infom[+];
//edge class requiredBy extends Dependency connect Infom[+] --> Infom[+];
// undirected:
//edge class correlatesWith extends Dependency connect Infom[+] --> Infom[+];
//
//  }
//
//}

/** A Change Impact Analysis workflow demonstation powered by locutor
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.4 */
//object Locutor {  
//  
//  def main(args: Array[String]) {
//    // Input
//    val src = "".toFile // source file
//    val tgt = "".toFile // target file
//    // Ad hoc configuration
//    val eqs = "".toFile // equivalence specification
//    val dep = "".toFile // dependency graph of source file
//    val rls = "".toFile // rules specification
//    // locutor system configuration
//    System.setProperty("locutor.tmp",    "/Users/nmueller/tmp/locutor")  // temporary directory
//    System.setProperty("locutor.grgen",  "/opt/grgen/bin")               // GrGen home directory
//    System.setProperty("locutor.equivs", "etc/kb/eq")                    // Knowledge base | Equivalence Specifications
//    System.setProperty("locutor.models", "etc/kb/gm")                    // Knowledge base | Graph Models
//    System.setProperty("locutor.rules",  "etc/kb/rs")                    // Knowledge base | Rule Systems
//      
//    // Semantic difference analysis
//    import scalaxx.diff.EquivalenceSystem
//    import scalaxx.diff.Differ.{diff => sdiff}    
//    val Δ = sdiff(eqs, src, tgt)
//    ()
                    
//    val depFile   = args(0).toFile
//    val equivFile = args(1).toFile
//    val ruleFile  = args(2).toFile
//    val oldFile   = args(3).toFile
//    val newFile   = args(4).toFile
//
//    println("============================================================================= DIFF")
//    //@future declarative syntax for equivalence systems
//    val ℰ = SVNBookEquivs // loadEquivalenceSystem(equivFile)
//    val Δ = for(δ <- diff(oldFile, newFile) withEquivs ℰ) yield δ match {
//      case cmd =>
//        println(new StringBuilder append "# " append cmd.prefix append " at " append cmd.path)
//        δ
//    }
//
//    println("========================================================================== KB(CIA)")
//    val Ｄ = loadDependencyGraph(depFile)
//    val ℛ = loadRuleSystem(ruleFile)
//
//    println("========================================================================= RIP(CIA)")
//    print("Rippling...")
//    rippleTimer.start
//                                      val ℒ = Ｄ ↩ Δ having ℛ
//    rippleTimer.stop
//    println(ident(33, "Done ("+rippleTimer+")."))
//
//    // flushing long-range effects
//    ℒ foreach (ℓ => flush(ℓ))    
//
//    println("======================================================================== MARK(RIP)")
//    mark(newFile, ℒ)    
//  } 
  
//  private def ident(offset: Int, string: String) =
//    (new StringBuilder /: (1 to offset))((b, i) => b append " ") append string

//  private def diff(oldFile: File, newFile: File) = new {
//    def withEquivs(equivs: scaup.eq.EquivalenceSystem[scala.xml.Node]) = {
//      print("Differencing...")
//      diffTimer.start
//      val delta = scalaxx.diff.Differ.diff(equivs, oldFile, newFile)
//      diffTimer.stop
//      println(ident(30, "Done ("+diffTimer+")."))
//      delta
//    }
//  }
  
//  private def loadDependencyGraph(description: File) = {
//    print("Loading dependency graph...")
//    dgTimer.start    
//    val dg = locutor.model.DependencyGraph.parse(description)    
//    dgTimer.stop
//    println(ident(18, "Done ("+dgTimer+")."))       
//    dg
//  }
  
//  private def loadRuleSystem(description: File) = {
//    print("Loading rule system...")
//    rsTimer.start    
//    val rs = locutor.model.RuleSystem.parse(description)    
//    rsTimer.stop
//    println(ident(23, "Done ("+rsTimer+")."))      
//    rs
//  }

//  private def flush(l: (scalaxx.diff.Command, locutor.cia.ImpactGraph)) = l match {
//    case (cmd, impact) =>
//      val buf = new StringBuilder append "# " append cmd.prefix append " at " append cmd.path append " has implicit effects on:\n"
//      (buf /: (impact.V filter (_.label("effect") contains "implicit")))((b, node) => {
//        b append "-> " append node.id append ":" append node.label("type").mkString append "\n      "
//        b append "in " append node.url append "\n      "
//        b append "at " append node.path append "\n" 
//      })   
//      println(buf)
//  } 
  
//  private def mark(file: File, L: Map[scalaxx.diff.Command, locutor.cia.ImpactGraph]) = {
//    import scalaxx.path._
//    import scala.xml.{Elem, Text, PrefixedAttribute, Null}    
//    val markers = Map(
//      (Root childAt 1) -> scalaxx.util.Mark(None, Some((Some(new PrefixedAttribute("xmlns", "locutor", Text("nrm"), Null)), None)), None)
//    ) ++ (L flatMap (l => l match {
//      case (cmd, impact) => impact.V filter (_.label("effect") contains "implicit") map (v =>
//        (v.path, scalaxx.util.Mark(
//          /* before */ None,
//          /* self   */ Some((None, Some(<locutor:affected from={cmd.path.toString} by={v.label("ct") mkString ","}></locutor:affected>))),
//          /* after  */ None))
//      )}))
//    val elem = scalaxx.util.Marker.mark(astOf(file), markers).elements.next
//    val markedFile = file.parentPath + "/" + file.name + ".affected." + file.ext.getOrElse("xml")
//    
//    val buf = new StringBuilder
//    buf append """<?xml version="1.0"?>"""
//    buf append """<!DOCTYPE book SYSTEM "/Users/nmueller/mydoc/svnbook/original/src/tools/dtd/docbook-4.4/docbookx.dtd">"""
//    buf append """<?xml-stylesheet type="text/css" href="styles.css"?>"""
//    buf append """<?xml-stylesheet type="text/xsl" href="../original/src/tools/html-stylesheet.xsl"?>"""
//    buf append scala.xml.Utility.toXML(elem)
//    buf.toString >>> markedFile.toFile 
//
//    println("Marked document: " + markedFile)
//  }
  
//  private def astOf(file: File) = scala.xml.XML.loadFile(file)

//println("Done ("+((dgTimer.elapsed+rsTimer.elapsed+rippleTimer.elapsed) / 1000.0)+" sec).\n")
  
//}